﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace MetaHeuristics.Aco
{
    using MetaHeuristics.Collections;

    public class AsDecisionRule : BaseDecisionRule
    {
        private float[] selectionProbabilities=null;

        public override void Initialize()
        {
            this.selectionProbabilities = new float[this.Aco.Cities.Count];
        }

        public override void MakeDecision(Ant ant)
        {
            int c = ant.LastCity;

            int j;
            do
            {
                float sumProbabilities = BuildWheel(ant, c);
                if (sumProbabilities < float.Epsilon)
                {
                    for (int i = 0; i < this.Aco.Cities.Count; ++i)
                    {
                        if (!ant.Visited(i))
                        {
                            ant.AddCity(i);
                            return;
                        }
                    }
                    throw new Exception();
                }
                else
                    j = SpunWheel(sumProbabilities);
            } while (ant.Visited(j));
            
            ant.AddCity(j);
        }

        public float[] GetSelectionProbabilities()
        {
            return this.selectionProbabilities;
        }

        protected virtual float BuildWheel(Ant ant, int c)
        {
            float sumProbabilities = 0;
            for (int j = 0; j < this.Aco.Cities.Count; ++j)
            {
                if (ant.Visited(j))
                    this.selectionProbabilities[j] = 0;
                else
                {
                    float choiceInfo = this.Aco.ChoiceInfos[c, j];
                    this.selectionProbabilities[j] = choiceInfo;
                    sumProbabilities += choiceInfo;
                }
            }
            return sumProbabilities;
        }

        protected int SpunWheel(float sumProbabilities)
        {
            double r = this.Rnd.NextDouble() * sumProbabilities;
            int j = 0;
            float p = this.selectionProbabilities[j];
            while (p < r)
            {
                j++;
                p += this.selectionProbabilities[j];
            }
            return j;
        }
    }
}
